#include "myc.h"

int stack=0,labels=0,sect=-1,strings=0;

void section(int sec) {
	if (sect==sec) return;
	switch (sect=sec) {
	case 0:
		fprintf(output,"section .data\n");
		break;
	case 1:
		fprintf(output,"section .text\n");
		break;
	case 2:
		fprintf(output,"section .bss\n");
		break;
	default:
		error("invalid section");
	}
}

void prhexa(char *str) {
	while (*str) fprintf(output,"%02hhX",*(str++));
}

void label(int la) {
	section(1);
	fprintf(output,"lab%d:\n",la);
}

void jmp(int la) {
	section(1);
	fprintf(output,"jmp lab%d\n",la);
}

void jmpp(int la) {
	section(1);
	fprintf(output,"jnz lab%d\n",la);
}

void jmpn(int la) {
	section(1);
	fprintf(output,"jz lab%d\n",la);
}

void setstack(int d) {
	section(1);
	if (d>0) fprintf(output,"add rsp,%d\n",d);
	if (d<0) fprintf(output,"sub rsp,%d\n",-d);
	stack+=d;
}

void set_top(int d) {
	section(1);
	fprintf(output,"mov rax,%d\nadd [rsp],rax\n",d);
}

void push_loc(int pl) {
	section(1);
	fprintf(output,"mov rax,rsp\nadd rax,%d\npush rax\n",pl-stack);
	stack-=PTR_SIZE;
}

void push_glob(char *name) {
	section(1);
	fprintf(output,"mov rax,var%s\npush rax\n",name);
	stack-=PTR_SIZE;
}

void push_int(short val) {
	section(1);
	fprintf(output,"mov ax,%hd\npush ax\n",val);
	stack-=INT_SIZE;
}

void push_char(char c) {
	section(1);
	fprintf(output,"mov al,%hhd\ndec rsp\nmov [rsp],al\n",c);
	stack-=1;
}

void push_string(struct token* tok) {
	section(0);
	fprintf(output,"str%d: DB ",++strings);
	int i;
	for (i=0;i<tok->len;i++) fprintf(output,"%c",tok->str[i]);
	fprintf(output,",0\n");
	section(1);
	fprintf(output,"mov rax,str%d\npush rax\n",strings);
	stack-=PTR_SIZE;
}

void call_func(char *name) {
	section(1);
	fprintf(output,"call func");
	prhexa(name);
	fprintf(output," ; %s\n",name);
}

void ret_func() {
	section(1);
	if (stack) fprintf(output,"add rsp,%d\n",-stack);
	fprintf(output,"ret\n");
}

void start_func(char *name) {
	section(1);
	fprintf(output,"global func");
	prhexa(name);
	fprintf(output," ; %s\nfunc",name);
	prhexa(name);
	fprintf(output,":\n");
}

void set_param(int par) {
	section(1);
	fprintf(output,"mov rcx,%d\n",par);
}

void ext_var(char *name) {
	fprintf(output,"extern var%s\n",name);
}

void ext_func(char *name) {
	fprintf(output,"extern func");
	prhexa(name);
	fprintf(output," ; %s\n",name);
}

void glb_var(char *name) {
	fprintf(output,"global var%s\n",name);
}

void set_var(char *name,int size) {
	section(2);
	fprintf(output,"var%s: resb %d\n",name,size);
}

void pop_cmp(int s) {
	section(1);
	switch (s) {
	case 1:
		fprintf(output,"mov al,[rsp]\ninc rsp\ncmp al,0\n");
		break;
	case 2:
		fprintf(output,"pop ax\ncmp ax,0\n");
		break;
	case 8:
		fprintf(output,"pop rax\ncmp rax,0\n");
		break;
	default:
		error("invalid condition size");
	}
	stack+=s;
}

void cmp_stack(int s) {
	section(1);
	switch (s) {
	case 1:
		fprintf(output,"mov al,[rsp]\ncmp al,0\n");
		break;
	case 2:
		fprintf(output,"mov ax,[rsp]\ncmp ax,0\n");
		break;
	case 8:
		fprintf(output,"mov rax,[rsp]\ncmp rax,0\n");
		break;
	default:
		error("invalid condition size");
	}
}
